# -*- coding: utf-8 -*-
# @File:     user_api.py
# @Author:
# @DateTime: 2025/06/25/11:13

import datetime
import json
import re
import time
from typing import Optional, Union, Any, List, Dict
from fastapi.encoders import jsonable_encoder
from sqlalchemy import or_
from sqlalchemy.orm import Session

from app.api.generate.utils.generate_utils import crud_generate_record
from app.api.generate.utils.redis_utils import key_add_order_queue
from app.api.generate.utils.rabbitmq_queue import queue_send_message
from app.api.system.schemas import users_schema
from app.conf import settings
from app.db.database import get_db
from app.models.generate import UserMembership
from app.models.system import Users
from app.utils import security
from app.utils.custom_exc import CustomException
from app.utils.custom_response import success_response, error_response
from fastapi import APIRouter, Query, Body, Path, Depends, UploadFile, Form, File, Request
from pydantic import BaseModel, Field

from app.utils.curd_base import ModelCRUD
from app.utils.file_storage import get_storage_file, save_storage_file, delete_storage_file
from app.utils.security import get_password_hash, verify_password
from app.utils.send_mail import send_mail_msg
from app.utils.throttle import IPThrottle
from app.utils.utils import get_now_time_string, selected_number_chrs
from app.utils.logger import logger

router = APIRouter()


def create_membership(user_id, db):
    data = {
        'total': 100,
        'user_id': user_id,
    }
    m = UserMembership(**data)  # type: ignore
    db.add(m)
    db.commit()
    db.refresh(m)


def checkemail(email):
    reg = r"\w+[@][a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+"
    result = re.findall(reg, email)
    if result:
        return True
    else:
        return False


class CRUDGenerateTask(ModelCRUD):

    model = Users


class SendCodeReqData(BaseModel):
    mail: str = Field(description='邮箱')


class RegisterReqData(BaseModel):
    mail: str = Field(description='邮箱')
    code: str = Field(description='验证码')
    password1: str = Field(description='密码')
    password2: str = Field(description='确认密码')


class EditUsernameReqData(BaseModel):
    username: str = Field(description='用户名')


class ResUsers(BaseModel):
    error_describe: Optional[str] = Field(default=None, description='错误描述')


class DeleteModel(BaseModel):
    id: list[int] = Field(description='ID列表')


class MyThrottle(IPThrottle):
    rate = "2/m"


@router.post("/send_code", summary="验证码", response_model=ResUsers,  dependencies=[], name='验证码')
async def register(
        request: Request,
        *,
        db: Session = Depends(get_db),
        req_data: SendCodeReqData,
        # ip=Depends(MyThrottle.allow_request)
) -> Any:
    """
    发送验证码
    :param request:
    :param db:
    :param req_data:
    :param ip:
    :return:
    """

    mail = req_data.mail

    if checkemail(mail) is False:
        return error_response(message='非法邮箱')

    user = db.query(Users).filter(Users.mail == mail).first()
    if user:
        return error_response(message='用户已注册')

    code = selected_number_chrs(6)
    cnn = request.app.state.redis
    await cnn.set(f'register_{mail}', code, 300)

    subject = '注册 Wchime'
    body = f'你好，你正在注册，当前验证码为{code}，有效时间为5分钟，请输入到验证框。'
    sender = settings.SMTP_SENDER
    smtp_server = settings.SMTP_SERVE
    smtp_port = settings.SMTP_PORT
    password = settings.SMTP_PWD

    ret, msg = send_mail_msg(subject, body, sender, mail, smtp_server, smtp_port, password)
    if ret is False:
        print(msg)
        logger.error(msg)
        return error_response(message='系统错误，请稍后再试')

    return success_response(message='发送成功')


@router.post("/retrieve_pwd_send_code", summary="pwd验证码", response_model=ResUsers, dependencies=[], name='pwd验证码')
async def register(
        request: Request,
        *,
        req_data: SendCodeReqData,
        db: Session = Depends(get_db),
        # ip=Depends(MyThrottle.allow_request)
) -> Any:
    """
    发送验证码
    :param request:
    :param db:
    :param ip:
    :param req_data:
    :return:
    """

    mail = req_data.mail

    if checkemail(mail) is False:
        return error_response(message='非法邮箱')

    user = db.query(Users).filter(Users.mail == mail).first()
    if not user:
        return error_response(message='用户未注册')

    code = selected_number_chrs(6)
    cnn = request.app.state.redis
    await cnn.set(f'retrieve_pwd_{mail}', code, 300)

    subject = 'Wchime 找回密码'
    body = f'你好，你正在找回密码，当前验证码为{code}，有效时间为5分钟，请输入到验证框。'
    sender = settings.SMTP_SENDER
    smtp_server = settings.SMTP_SERVE
    smtp_port = settings.SMTP_PORT
    password = settings.SMTP_PWD

    ret, msg = send_mail_msg(subject, body, sender, mail, smtp_server, smtp_port, password)
    if ret is False:
        print(msg)
        logger.error(msg)
        return error_response(message='系统错误，请稍后再试')

    return success_response(message='发送成功')


@router.post("/register", summary="注册", response_model=ResUsers,  dependencies=[], name='注册')
async def register(
        request: Request,
        *,
        db: Session = Depends(get_db),
        req_data: RegisterReqData,
) -> Any:
    """
    用户注册
    :param request:
    :param db:
    :param req_data:
    :return:
    """

    mail = req_data.mail
    code = req_data.code
    if checkemail(mail) is False:
        return error_response(message='非法邮箱')

    if req_data.password1 != req_data.password2:
        return error_response(message='两次密码不一致')

    cnn = request.app.state.redis

    cache_code = await cnn.get(f'register_{mail}')
    if cache_code is None:
        return error_response(message='验证码已过期')
    if cache_code != code:
        return error_response(message='验证码不正确')

    hashed_password = get_password_hash(req_data.password1)
    obj_dict = {
        'nickname': mail,
        'username': mail,
        'hashed_password': hashed_password,
        'mail': mail,
    }
    user = Users(**obj_dict)  # type: ignore
    db.add(user)
    db.commit()
    db.refresh(user)

    token_dict = security.create_token(user.id)
    create_membership(user.id, db)

    resp = {
        'id': user.id,
        'nickname': user.nickname,
        'username': user.username,
        'avatar': get_storage_file(user.avatar),
        'mail': user.mail,
    }
    resp.update(token_dict)
    return success_response(data=resp)


@router.post("/edit_username", summary="修改用户名", response_model=ResUsers,  dependencies=[], name='修改用户名')
async def register(
        request: Request,
        *,
        db: Session = Depends(get_db),
        req_data: EditUsernameReqData,
        current_user: Users = Depends(security.verify_access_token),
) -> Any:

    username = req_data.username

    if len(username) < 4:
        return error_response(message='用户名不能小于4个字符')

    has_user = db.query(Users).filter(Users.username == username).first()
    if has_user:
        return error_response(message='用户名已存在')

    user = db.query(Users).filter(Users.id == int(current_user.id)).first()

    user.username = username
    user.nickname = username

    db.add(user)
    db.commit()
    db.refresh(user)
    resp = {
        'id': user.id,
        'nickname': user.nickname,
        'username': user.username,
        'avatar': get_storage_file(user.avatar),
        'mail': user.mail,
    }

    return success_response(resp, message='修改成功')


@router.post("/retrieve_pwd", summary="找回密码", response_model=ResUsers,  dependencies=[], name='找回密码')
async def register(
        request: Request,
        *,
        db: Session = Depends(get_db),
        req_data: RegisterReqData,
) -> Any:
    """
    用户注册
    :param request:
    :param db:
    :param req_data:
    :return:
    """

    mail = req_data.mail
    code = req_data.code
    if checkemail(mail) is False:
        return error_response(message='非法邮箱')

    if req_data.password1 != req_data.password2:
        return error_response(message='两次密码不一致')

    cnn = request.app.state.redis

    cache_code = await cnn.get(f'retrieve_pwd_{mail}')
    if cache_code is None:
        return error_response(message='验证码已过期')
    if cache_code != code:
        return error_response(message='验证码不正确')

    hashed_password = get_password_hash(req_data.password1)

    user = db.query(Users).filter(Users.mail == mail).first()

    user.hashed_password = hashed_password
    db.add(user)
    db.commit()
    db.refresh(user)
    return success_response(message='修改成功')


@router.post("/login", summary="用户登录", response_model=users_schema.LoginResp, name='用户登录')
async def login_access_token(
        *,
        db: Session = Depends(get_db),
        user_info: users_schema.UsernameAuth,
) -> Any:
    """
    用户登录
    :param db:
    :param user_info:
    :return:
    """

    username = user_info.username
    password = user_info.password

    user = db.query(Users).filter(Users.mail == username).first()
    if not user:
        user = db.query(Users).filter(Users.username == username).first()
    if not user:
        return error_response(message="用户名或者密码错误")
    if not verify_password(password, user.hashed_password):
        return error_response(message="用户名或者密码错误")
    if user.is_active == 0:
        return error_response(message="用户被禁用,请联系管理员")

    token_dict = security.create_token(user.id)
    # resp = dict()
    # resp['token'] = token_dict
    resp = {
        'id': user.id,
        'nickname': user.nickname,
        'username': user.username,
        'avatar': get_storage_file(user.avatar),
        'mail': user.mail,
    }
    resp.update(token_dict)
    return success_response(data=resp)

